package com.hnas.sys.core.spring;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.hnas.core.util.StringUtil;
import com.hnas.sys.core.util.UserUtils;
import com.hnas.sys.exception.InvalidVisitException;
import com.hnas.sys.exception.MethodErrorException;
import com.hnas.sys.exception.ValidationCodeException;

public class UsernamePasswordAuthenticationExtendFilter extends
		UsernamePasswordAuthenticationFilter {

	// 验证码字段
	private String validateCodeParameter = "validateCode";
	private String smsCodeParameter = "validateSmsCode";
	// 是否开启验证码功能
	private boolean openValidateCode = false;
	private boolean openSmsCode = false;

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.springframework.security.web.authentication.
	 * UsernamePasswordAuthenticationFilter
	 * #attemptAuthentication(javax.servlet.http.HttpServletRequest,
	 * javax.servlet.http.HttpServletResponse)
	 */
	public Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException {
		//验证refer
		if (!request.isRequestedSessionIdValid()){
			response.setStatus(403);
//			return;
			throw new InvalidVisitException("非法访问！");
		}
		String refer = request.getHeader("REFERER");
		if (null==refer || (refer.indexOf("/login.jsp")<0)){
			//logger.error("refer:"+refer);
			//response.setStatus(403);
//			return;
			//throw new InvalidVisitException("非法访问！");
		}
		// 只接受POST方式传递的数据
		if (!"POST".equals(request.getMethod()))
			throw new MethodErrorException("不支持非POST方式的请求!");

		// 开启验证码功能的情况
		if (isOpenValidateCode() || this.openSmsCode)
			checkValidateCode(request);
		
		HttpSession session = request.getSession(false);
		Object lastRequest = null;
		if (null!=session){
			logger.error("athen Session1:"+session.getId());
//			Enumeration em = session.getAttributeNames();
//			while (em.hasMoreElements()) {
//				String paraName = (String) em.nextElement();
//				logger.error("Session attribute:"+paraName+"/"+session.getAttribute(paraName));
//			}
			lastRequest = session.getAttribute("SPRING_SECURITY_SAVED_REQUEST");
			session.invalidate();//清空session
			if (null!=request.getCookies() && request.getCookies().length>0){
				Cookie cookie = request.getCookies()[0];//获取cookie
		    	cookie.setMaxAge(0);//让cookie过期
			}
			
		}
		HttpSession session2 = request.getSession(true);
		session2.setAttribute("SPRING_SECURITY_SAVED_REQUEST", lastRequest);

		// 获取Username和Password
		String username = obtainUsername(request);
		String password = obtainPassword(request);

		// UsernamePasswordAuthenticationToken实现Authentication校验
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
				username, password);
		//String passwordStr = new Md5PasswordEncoder().encodePassword(password, username);
		//System.out.println("password:"+passwordStr);
		// 允许子类设置详细属性
		setDetails(request, authRequest);

		// 运行UserDetailsService的loadUserByUsername 再次封装Authentication
		return this.getAuthenticationManager().authenticate(authRequest);
	}

	// 匹对验证码的正确性
	public void checkValidateCode(HttpServletRequest request) {

		
	
		/*
		 * boolean b = CaptchaServiceSingleton.getInstance()
		 * .validateResponseForID(request.getSession().getId(), jcaptchaCode);
		 * if (!b) throw new ValidationCodeException("验证码不正确,请重新输入!");
		 */
		
		// 从Session中取出验证码
		if (this.openSmsCode){
			String jcaptchaCode = obtainSmsValidateCodeParameter(request);
			if (StringUtil.isEmpty(jcaptchaCode))
				throw new ValidationCodeException("请输入验证码！");
			String ssnValidationCode = this.obtainSmsValidateCode(request);
			
			if (!jcaptchaCode.equals(ssnValidationCode)) {
				// 用户输入的值与看到的不一致,抛出异常
				throw new ValidationCodeException("验证码不正确！");
			}
		}
		if (this.openValidateCode){
			String jcaptchaCode = obtainValidateCodeParameter(request);
			if (StringUtil.isEmpty(jcaptchaCode))
				throw new ValidationCodeException("请输入验证码！");
			String ssnValidationCode = this.obtainSessionValidateCode(request);

			if (!jcaptchaCode.equals(ssnValidationCode)) {
				// 用户输入的值与看到的不一致,抛出异常
				throw new ValidationCodeException("验证码不正确！");
			}
		}
		
		

	}

	private String obtainValidateCodeParameter(HttpServletRequest request) {
		return request.getParameter(validateCodeParameter);
	}
	private String obtainSmsValidateCodeParameter(HttpServletRequest request) {
		return request.getParameter(this.smsCodeParameter);
	}

	protected String obtainSessionValidateCode(HttpServletRequest request) {
		Object obj = request.getSession().getAttribute(
				UserUtils.MIX_IMG_CODE);
		request.getSession().setAttribute(UserUtils.MIX_IMG_CODE, null);
		return null == obj ? "" : obj.toString();
	}
	protected String obtainSmsValidateCode(HttpServletRequest request) {
		Object obj = request.getSession().getAttribute(
				UserUtils.MIX_SMS_CODE_BACK);
//		request.getSession().setAttribute(UserUtils.MIX_IMG_CODE, null);
		return null == obj ? "" : obj.toString();
	}

	@Override
	protected String obtainUsername(HttpServletRequest request) {
		Object obj = request.getParameter(getUsernameParameter());
		return null == obj ? "" : obj.toString().trim();
	}

	@Override
	protected String obtainPassword(HttpServletRequest request) {
		Object obj = request.getParameter(getPasswordParameter());
		return null == obj ? "" : obj.toString().trim();
	}

	public String getValidateCodeParameter() {
		return validateCodeParameter;
	}

	public void setValidateCodeParameter(String validateCodeParameter) {
		this.validateCodeParameter = validateCodeParameter;
	}

	public boolean isOpenValidateCode() {
		return openValidateCode;
	}

	public void setOpenValidateCode(boolean openValidateCode) {
		this.openValidateCode = openValidateCode;
	}

	public String getSmsCodeParameter() {
		return smsCodeParameter;
	}

	public void setSmsCodeParameter(String smsCodeParameter) {
		this.smsCodeParameter = smsCodeParameter;
	}

	public boolean isOpenSmsCode() {
		return openSmsCode;
	}

	public void setOpenSmsCode(boolean openSmsCode) {
		this.openSmsCode = openSmsCode;
	}

}
